﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace ParticleFiltersDemo1
{
    public class Particle : ViewModelBase
    {
        private double x;
        private double y;
        public double heading;
        public double weight;
        bool isNoisy; 
        Board board;

        /*
         * Distance to the obstacle in the same direction as heading
         */
        public int getDistToOpsticel() 
        {
            int distToOpsticle = 0;
            double orientation = heading*Math.PI/180;
            if (Math.Round(Math.Sin(orientation)) == 0 && Math.Round(Math.Cos(orientation)) == 1) // DOWN
            {
                while (board.IsEmpty((int)(x), (int)(y + 1)))
                {
                    distToOpsticle++;
                }
                
            }
            else if (Math.Round(Math.Sin(orientation)) == 1 && Math.Round(Math.Cos(orientation)) == 0) // RIGHT
            {
                while (board.IsEmpty((int)(x++), (int)(y )))
                {
                    distToOpsticle++;
                }
            }
            else if (Math.Round(Math.Sin(orientation)) == -1 && Math.Round(Math.Cos(orientation)) == 0) // LEFT
            {
                while (board.IsEmpty((int)(x-1), (int)(y)))
                {
                    distToOpsticle++;
                }
            }
            else
            {
                 while (board.IsEmpty((int)(x), (int)(y - 1)))
                {
                    distToOpsticle++;
                }
            }

            return distToOpsticle;
        }

        public double X
        {
            get
            {
                return this.x;
            }
            set
            {
                if ( this.x == value )
                    return;

                this.x = value;
                this.NotifyPropertyChanged( "X" );
            }
        }

        public double Y
        {
            get
            {
                return this.y;
            }
            set
            {
                if ( this.y == value )
                    return;

                this.y = value;
                this.NotifyPropertyChanged( "Y" );
            }
        }

        public Action PositionChanged;

        public Particle( double x, double y, double heading, double weight, bool isNoisy, Board board )
        {
            this.x = x;
            this.y = y;
            this.heading = heading;
            this.weight = weight;
            this.isNoisy = isNoisy;
            if ( this.isNoisy )
            {
                AddNoise();

            }
            this.board = board;

        }
        
        //If we do not know the heading
        public Particle( double x, double y, double weight, bool isNoisy, Board board )
            : this( x, y, -1, weight, isNoisy, board )
        {
            this.heading = 0;
        }

        public bool IsNextToObstacle
        {
            get
            {
                int gridx = ( int )this.X;
                int gridy = ( int )this.Y;
                double orientation = heading * Math.PI / 180;//!!!!!!!!

                if (Math.Sin(orientation) == 1 && Math.Cos(orientation) == 0) // RIGHT - EAST
                {
                    gridx++;
                }
                else if (Math.Sin(orientation) == -1 && Math.Cos(orientation) == 0) // LEFT
                {
                    gridx--;
                }
                else if (Math.Sin(orientation) == 0 && Math.Cos(orientation) == 1) // DOWN
                {
                    gridy++;
                }
                else
                {
                    gridy--;
                }

                if ( gridx < 0 || gridy < 0 || gridx >= this.board.sizeX || gridy >= this.board.sizeY )
                    return true;

                return !( this.board.IsEmpty( gridx, gridy ) );
            }
        }

        public void AddNoise()
        {
            Random r = new Random();
            this.x += ( double )r.Next( -1, 1 ) / 10;
            this.y += ( double )r.Next( -1, 1 ) / 10;
            this.heading += ( double )r.Next( -1, 1 ) / 10;

        }

        public void SetHeading( double h )
        {
            heading = h;
        }

        /*
         * Moves the particle.
         * Return true if moved.
         */
        public bool AdvanceBy( double speed, bool noisy )
        {
            if ( noisy )
            {
                Random r = new Random();
                heading += r.Next( -3, 3 );
            }

            double rad = heading * Math.PI / 180;
            double dx =  Math.Sin( rad ) * speed;
            double dy = Math.Cos( rad ) * speed;
            
            if ( board.IsEmpty( ( int )( x + dx ), ( int )( y + dy ) ) )
            {
                x += dx;
                y += dy;            

                return true;
            }

            return false;
        }

        public Particle Clone()
        {
            Particle clone = new Particle( this.X, this.Y, this.weight, this.isNoisy, this.board );
            clone.heading = this.heading;

            return clone;
        }
    }
}
